{% extends "templates/web.html" %}

{% block page_content %}
<style>
.tracking-container {
    width: 100%;
    min-height: 100vh;
    margin: 0;
    padding: 0;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: #f8f9fa;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
}

.tracking-search {
    background: white;
    padding: 20px;
    display: flex;
    gap: 15px;
    align-items: center;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.tracking-search .input-group {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.tracking-search .input-group span:first-child {
    font-size: 16px;
    font-weight: 600;
    color: #343a40;
}

.tracking-search .input-group span:last-child {
    font-size: 12px;
    color: #6c757d;
}

.tracking-search button {
    background: #dc3545;
    color: white;
    border: none;
    padding: 12px 24px;
    border-radius: 6px;
    font-size: 16px;
    cursor: pointer;
    transition: background-color 0.3s;
    font-weight: 600;
}

.tracking-search button:hover {
    background: #c82333;
}

.tracking-search .search-box {
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: 360px;
    width: 100%;
}

.tracking-search input[type="text"] {
    flex: 1;
    padding: 10px 14px;
    border: 1px solid #ced4da;
    border-radius: 6px;
    font-size: 14px;
    background: #fff;
}

.tracking-search input[type="text"]:focus {
    outline: none;
    border-color: #007bff;
    box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.15);
}

.status-filter {
    background: white;
    padding: 15px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.filter-tabs {
    display: flex;
    gap: 20px;
}

.filter-tab {
    padding: 8px 16px;
    border-radius: 20px;
    cursor: pointer;
    transition: all 0.3s;
    font-size: 14px;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 8px;
    background: #f8f9fa;
    color: #6c757d;
}

.filter-tab.active {
    background: #dc3545;
    color: white;
}

.filter-tab:not(.active):hover {
    background: #e9ecef;
    color: #495057;
}

.export-btn {
    background: #dc3545;
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 8px;
}

.export-btn:hover {
    background: #c82333;
}

.tracking-results {
    background: white;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    overflow: hidden;
    flex: 1;
    display: flex;
    flex-direction: column;
}

.tracking-table {
    width: 100%;
    border-collapse: collapse;
    flex: 1;
    display: flex;
    flex-direction: column;
}

.tracking-table thead {
    background: #28a745;
    color: white;
    display: table;
    width: 100%;
    table-layout: fixed;
}

.tracking-table th,
.tracking-table td {
    padding: 15px 12px;
    text-align: left;
    font-size: 14px;
}

.tracking-table tbody {
    flex: 1;
    overflow-y: auto;
    display: block;
}

.tracking-table tbody tr {
    border-bottom: 1px solid #e9ecef;
    cursor: pointer;
    transition: all 0.3s ease;
    display: table;
    width: 100%;
    table-layout: fixed;
}

.tracking-table tbody tr:hover {
    background: #f8f9fa;
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.tracking-table tbody tr.selected {
    background: #e8f5e8;
    border-left: 4px solid #28a745;
}

.tracking-number {
    font-weight: 600;
    color: #007bff;
}

.tracking-route {
    font-size: 12px;
    color: #6c757d;
    margin-top: 4px;
}

.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 500;
}

.status-badge.delivered { background: #d4edda; color: #155724; }
.status-badge.processing { background: #fff3cd; color: #856404; }
.status-badge.transit { background: #cce5ff; color: #004085; }
.status-badge.not-found { background: #f8d7da; color: #721c24; }
.status-badge.alert { background: #f5c6cb; color: #721c24; }
.status-badge.returned { background: #e2e3e5; color: #383d41; }

.last-event {
    font-size: 13px;
    color: #495057;
    line-height: 1.4;
}

.tracking-detail {
    display: none;
    background: #f8f9fa;
    border-top: 1px solid #e9ecef;
}

.tracking-detail.expanded {
    display: table-row;
}

.detail-actions {
    padding: 15px 20px;
    border-bottom: 1px solid #e9ecef;
    display: flex;
    gap: 10px;
}

.detail-btn {
    background: #6c757d;
    color: white;
    border: none;
    padding: 6px 12px;
    border-radius: 4px;
    font-size: 12px;
    cursor: pointer;
}

.detail-content {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 20px;
    padding: 20px;
}

.timeline-item {
    display: flex;
    align-items: flex-start;
    margin-bottom: 15px;
    position: relative;
    padding-left: 20px;
}

.timeline-item:not(:last-child)::before {
    content: '';
    position: absolute;
    left: 8px;
    top: 20px;
    bottom: -15px;
    width: 2px;
    background: #e9ecef;
}

.timeline-item::after {
    content: '';
    position: absolute;
    left: 6px;
    top: 16px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #6c757d;
}

.timeline-time {
    font-size: 13px;
    color: #6c757d;
    margin-bottom: 4px;
}

.timeline-event {
    font-size: 14px;
    color: #333;
    font-weight: 500;
}

.info-row {
    display: flex;
    justify-content: space-between;
    margin-bottom: 10px;
    padding-bottom: 10px;
    border-bottom: 1px solid #e9ecef;
}

.info-label {
    color: #6c757d;
    font-size: 13px;
}

.info-value {
    color: #333;
    font-size: 13px;
    font-weight: 500;
}

.loading,
.error {
    text-align: center;
    padding: 40px;
}

.error {
    background: #f8d7da;
    color: #721c24;
    margin: 20px;
    border: 1px solid #f5c6cb;
    border-radius: 6px;
}

@media (max-width: 768px) {
    .tracking-search {
        flex-direction: column;
        align-items: stretch;
    }
    .status-filter {
        flex-direction: column;
        gap: 12px;
        align-items: stretch;
    }
    .detail-content {
        grid-template-columns: 1fr;
    }
}
</style>

<div class="tracking-container">
    <div class="tracking-search">
        <div class="input-group">
            <span>当前用户可访问的全部在途物流单</span>
            <span>页面自动加载，无需筛选，可随时点击刷新。</span>
        </div>
        <div class="search-box">
            <input type="text" id="trackingSearchInput" placeholder="输入/粘贴跟踪号、订单号或客户名称过滤" />
        </div>
        <button id="refreshBtn">刷新</button>
    </div>

    <div class="status-filter">
        <div class="filter-tabs">
            <div class="filter-tab active" data-status="all">📦 All(<span id="allCount">0</span>)</div>
            <div class="filter-tab" data-status="processing">⚙ Processing(<span id="processingCount">0</span>)</div>
            <div class="filter-tab" data-status="transit">✈ Transit(<span id="transitCount">0</span>)</div>
            <div class="filter-tab" data-status="delivered">✔ Delivered(<span id="deliveredCount">0</span>)</div>
            <div class="filter-tab" data-status="not-found">✗ Not Found(<span id="notFoundCount">0</span>)</div>
            <div class="filter-tab" data-status="alert">⚠ Alert(<span id="alertCount">0</span>)</div>
            <div class="filter-tab" data-status="returned">↻ Returned(<span id="returnedCount">0</span>)</div>
        </div>
        <button class="export-btn" id="exportBtn">📋 Copy & Export</button>
    </div>

    <div id="trackingResults" class="tracking-results" style="display:none;">
        <table class="tracking-table">
            <thead>
                <tr>
                    <th>运单号</th>
                    <th>客户单号</th>
                    <th>跟踪号</th>
                    <th>ERP订单</th>
                    <th>运输方式</th>
                    <th>收件人国家</th>
                    <th>创建时间</th>
                    <th>收货时间</th>
                    <th>发货时间</th>
                    <th>签收时间</th>
                    <th>最新事件时间</th>
                    <th>最新事件</th>
                    <th>状态</th>
                    <th>承运商</th>
                </tr>
            </thead>
            <tbody id="trackingTableBody"></tbody>
        </table>
    </div>

    <div id="loadingState" class="loading" style="display:none;">
        <p>正在查询物流信息，请稍候…</p>
    </div>

    <div id="errorState" class="error" style="display:none;">
        <p id="errorMessage">暂无数据</p>
    </div>
</div>

<script>
let shipments = [];
let trackingData = [];
let renderedData = [];
let currentFilter = 'all';
let searchKeyword = '';

document.addEventListener('DOMContentLoaded', () => {
    bindFilterTabs();
    bindExport();

    const refreshBtn = document.getElementById('refreshBtn');
    if (refreshBtn) refreshBtn.addEventListener('click', refreshShipments);

    const searchInput = document.getElementById('trackingSearchInput');
    if (searchInput) {
        searchInput.addEventListener('input', (event) => {
            searchKeyword = (event.target.value || '').trim().toLowerCase();
            renderTable();
        });
    }

    refreshShipments();
});

async function refreshShipments() {
    showLoading();
    try {
        const resp = await frappe.call({
            method: 'upsystem.upsystem.api_tms_tracking.get_shop_shipments'
        });
        const message = resp.message || {};
        shipments = message.shipments || [];
        await rebuildTrackingData();
    } catch (err) {
        console.error(err);
        showError('同步物流信息失败: ' + (err.message || err));
    }
}

async function rebuildTrackingData() {
    const orderKeys = [...new Set(
        shipments
            .map(s => (s.custom_delivery_order_no || '').trim())
            .filter(key => !!key)
    )];

    const orderTrackMap = {};

    if (orderKeys.length) {
        const orderResp = await frappe.call({
            method: 'upsystem.upsystem.api.batch_tracking',
            args: { tracking_numbers: orderKeys }
        });
        const orderMsg = orderResp.message || {};
        (orderMsg.data || []).forEach((item, idx) => {
            if (!item) return;
            const data = item.data || {};
            const candidateKeys = new Set();
            const queryKey = (item.query_tracking_number || orderKeys[idx] || '').trim();
            if (queryKey) candidateKeys.add(queryKey);
            const displayKey = (item.tracking_number || '').trim();
            if (displayKey) candidateKeys.add(displayKey);
            const dataTracking = (data.tracking_number || '').trim();
            if (dataTracking) candidateKeys.add(dataTracking);
            const dataOrder = (data.order_number || '').trim();
            if (dataOrder) candidateKeys.add(dataOrder);
            const dataWaybill = (data.waybill_number || '').trim();
            if (dataWaybill) candidateKeys.add(dataWaybill);
            const lastMile = (data.last_mile_tracking || '').trim();
            if (lastMile) candidateKeys.add(lastMile);
            candidateKeys.forEach(key => {
                if (key && !orderTrackMap[key]) {
                    orderTrackMap[key] = item;
                }
            });
        });
    }

    trackingData = shipments.map(shipment => {
        const trackingNumber = (shipment.custom_delivery_no || '').trim();
        const deliveryOrderNo = (shipment.custom_delivery_order_no || shipment.name || '').trim();

        const orderTrack =
            orderTrackMap[deliveryOrderNo] ||
            orderTrackMap[shipment.name] ||
            orderTrackMap[trackingNumber] ||
            null;

        let lastMileTracking = '';
        if (orderTrack && orderTrack.data) {
            lastMileTracking = (orderTrack.data.last_mile_tracking || '').trim();
        }

        return buildTrackingRecord(shipment, orderTrack, {
            trackingNumber,
            deliveryOrderNo,
            lastMileTracking
        });
    });

    renderTable();
}

function normalizeStatus(value) {
    const raw = (value || '').toString().toLowerCase();
    if (raw === 'delivered') return 'delivered';
    if (raw === 'returned') return 'returned';
    if (raw === 'not-found' || raw === 'not_found') return 'not-found';
    if (raw === 'exception' || raw === 'alert') return 'alert';
    if (raw === 'in_transit' || raw === 'transit' || raw === 'out_for_delivery') return 'transit';
    if (raw === 'processing' || raw === 'pending') return 'processing';
    return 'processing';
}

function extractTrackSnapshot(track) {
    const snapshot = {
        status: null,
        history: [],
        route: null,
        carrierInfo: {},
        event: null,
        eventTimestamp: null,
        eventTimestampMs: null,
        creationTimestamp: null,
        creationTimestampMs: null,
        destinationCode: null,
        productName: null,
        trackingNumber: null,
        checkInTime: null,
        checkOutTime: null,
        deliveredTime: null
    };

    if (!track || !track.data) {
        return snapshot;
    }

    const data = track.data || {};
    snapshot.status = data.status || data.package_status || null;
    snapshot.route = data.route || null;
    snapshot.carrierInfo = data.carrier_info || {};
    snapshot.productName = data.product_name || null;
    snapshot.trackingNumber = data.tracking_number || null;
    snapshot.checkInTime = data.check_in_time || null;
    snapshot.checkOutTime = data.check_out_time || null;

    const historySource = Array.isArray(data.tracking_history) ? data.tracking_history : [];
    snapshot.history = historySource.slice();

    const latestEvent = historySource.find(ev => ev && ev.timestamp) || historySource[0];
    if (latestEvent) {
        const rawTime = latestEvent.timestamp || latestEvent.process_time || '';
        const eventText = latestEvent.description || latestEvent.event || '';
        snapshot.eventTimestamp = rawTime;
        snapshot.event = rawTime ? `${rawTime} · ${eventText}`.trim() : eventText;
        const timestampValue = Date.parse(rawTime);
        snapshot.eventTimestampMs = Number.isNaN(timestampValue) ? null : timestampValue;
    } else if (data.last_event || track.message) {
        snapshot.event = (data.last_event || track.message || '').trim();
    }

    // earliest/creation time
    if (historySource && historySource.length) {
        let minMs = null;
        let minRaw = null;
        historySource.forEach(ev => {
            const raw = ev.timestamp || ev.process_time || '';
            const ms = Date.parse(raw);
            if (!Number.isNaN(ms) && (minMs === null || ms < minMs)) {
                minMs = ms;
                minRaw = raw;
            }
        });
        if (minMs !== null) {
            snapshot.creationTimestampMs = minMs;
            snapshot.creationTimestamp = minRaw;
        }
    }

    // destination code from route CN → US
    if (snapshot.route && snapshot.route.includes('→')) {
        const parts = snapshot.route.split('→').map(s => (s || '').trim());
        if (parts.length >= 2) snapshot.destinationCode = parts[1];
    }

    // delivered time if exists
    if (historySource && historySource.length) {
        const delivered = historySource.find(ev => {
            const code = (ev.track_node_code || ev.status || '').toString().toUpperCase();
            const desc = (ev.description || ev.event || ev.process_content || '').toString().toLowerCase();
            return code === 'DELIVERED' || desc.includes('delivered') || desc.includes('已签收') || desc.includes('签收');
        });
        if (delivered) {
            const raw = delivered.timestamp || delivered.process_time || '';
            const ms = Date.parse(raw);
            snapshot.deliveredTime = !Number.isNaN(ms) ? raw : null;
        }
    }

    return snapshot;
}

function buildTrackingRecord(shipment, orderTrack, numbers) {
    const trackingNumber = numbers?.trackingNumber || shipment.custom_delivery_no || '';
    const deliveryOrderNo = numbers?.deliveryOrderNo || shipment.custom_delivery_order_no || shipment.name || '';
    const lastMileTracking = numbers?.lastMileTracking || '';

    const orderSnapshot = extractTrackSnapshot(orderTrack);

    const baseStatus = orderSnapshot.status;
    const statusKey = normalizeStatus(baseStatus || 'processing');

    const fallbackRoute = shipment.custom_country ? `CN → ${shipment.custom_country}` : 'CN → Unknown';
    const route = orderSnapshot.route || fallbackRoute;

    const lastOrderEvent = orderSnapshot.event || '等待轨迹更新';

    const carrierInfo = orderSnapshot.carrierInfo || {};
    const latestTimestamp = orderSnapshot.eventTimestampMs ?? null;
    const creationTimestamp = orderSnapshot.creationTimestampMs ?? null;
    const destinationCode = orderSnapshot.destinationCode || (shipment.custom_country || '').trim();
    const productName = orderSnapshot.productName || '';
    const trackNumResolved = orderSnapshot.trackingNumber || trackingNumber;
    const checkInTime = orderSnapshot.checkInTime || null;
    const checkOutTime = orderSnapshot.checkOutTime || null;
    const deliveredTime = orderSnapshot.deliveredTime || null;

    return {
        deliveryOrderNo,
        trackingNumber: trackNumResolved,
        statusKey,
        deliveryStatus: getStatusInfo(statusKey),
        lastOrderEvent,
        route,
        orderNumber: shipment.custom_shopify_order_id || shipment.po_no || '-',
        orderName: shipment.name,
        customer: shipment.customer_name || '-',
        orderStatus: shipment.status || '-',
        company: shipment.company || '-',
        logisticsOrderNo: shipment.name || '-',
        lastMileTracking,
        productName,
        destinationCode,
        creationTimestamp,
        checkInTime,
        checkOutTime,
        deliveredTime,
        carrierInfo,
        shipment,
        latestTimestamp,
        detailLoaded: false,
        detailLoading: false,
        detailHistory: null,
        detailPromise: null,
        detailMeta: {}
    };
}

function renderTable() {
    const tbody = document.getElementById('trackingTableBody');
    if (!tbody) return;

    let data = trackingData.slice();

    if (searchKeyword) {
        data = data.filter(item =>
            [
                item.deliveryOrderNo,
                item.trackingNumber,
                item.orderNumber,
                item.orderName,
                item.productName,
                item.destinationCode,
                item.lastOrderEvent
            ]
                .some(field => (field || '').toLowerCase().includes(searchKeyword))
        );
    }

    if (currentFilter !== 'all') {
        data = data.filter(item => item.statusKey === currentFilter);
    }

    data.sort((a, b) => (b.latestTimestamp || 0) - (a.latestTimestamp || 0));
    renderedData = data;

    updateStatusCounts(data);

    tbody.innerHTML = '';

    data.forEach((item, index) => {
        const sourceIndex = trackingData.indexOf(item);
        if (sourceIndex === -1) return;
        const row = document.createElement('tr');
        row.className = 'tracking-row';
        row.dataset.status = item.statusKey || 'processing';
        row.dataset.index = sourceIndex;
        row.innerHTML = `
            <td><div class="tracking-number">${item.deliveryOrderNo || '-'}</div></td>
            <td>${item.trackingNumber || '-'}</td>
            <td>
                <div>${item.orderName}</div>
                <div class="tracking-route">${item.orderNumber || '-'}</div>
            </td>
            <td>${item.productName || '-'}</td>
            <td>${item.destinationCode || '-'}</td>
            <td>${item.creationTimestamp ? formatTimelineTime(item.creationTimestamp) : '-'}</td>
            <td>${item.checkInTime ? formatTimelineTime(item.checkInTime) : '-'}</td>
            <td>${item.checkOutTime ? formatTimelineTime(item.checkOutTime) : '-'}</td>
            <td>${item.deliveredTime ? formatTimelineTime(item.deliveredTime) : '-'}</td>
            <td>${item.latestTimestamp ? formatTimelineTime(item.latestTimestamp) : '-'}</td>
            <td><div class="last-event">${item.lastOrderEvent || '-'}</div></td>
            <td>
                <div class="status-badge ${item.deliveryStatus.class}">
                    <span>${item.deliveryStatus.icon}</span>
                    <span>${item.deliveryStatus.text}</span>
                </div>
            </td>
            <td>${renderCarrierCell(item)}</td>
        `;
        row.addEventListener('click', () => toggleTrackingDetail(row, detailRow));
        tbody.appendChild(row);

        const detailRow = document.createElement('tr');
        detailRow.className = 'tracking-detail';
        detailRow.dataset.index = sourceIndex;
        detailRow.style.display = 'none';
        detailRow.innerHTML = `
            <td colspan="4">
                <div class="detail-actions">
                    <button class="detail-btn" onclick="copyTrackingHistory(${sourceIndex})">复制轨迹</button>
                    <button class="detail-btn" onclick="copyLink(${sourceIndex})">复制查询链接</button>
                </div>
                <div class="detail-content">
                    <div>
                        <h4>Tracking History</h4>
                        <div class="timeline-container" id="timeline-${sourceIndex}"><p>点击左侧行以加载轨迹</p></div>
                    </div>
                    <div>
                        <h4>Shipment Info</h4>
                        <div class="info-row"><span class="info-label">ERP订单</span><span class="info-value">${item.orderName}</span></div>
                        <div class="info-row"><span class="info-label">Tracking #</span><span class="info-value" id="detail-tracking-${sourceIndex}">${item.trackingNumber || '-'}</span></div>
                        <div class="info-row"><span class="info-label">Last Mile #</span><span class="info-value" id="detail-last-mile-${sourceIndex}">${item.lastMileTracking || '-'}</span></div>
                        <div class="info-row"><span class="info-label">Delivery Order No</span><span class="info-value">${item.deliveryOrderNo || '-'}</span></div>
                        <div class="info-row"><span class="info-label">Route</span><span class="info-value" id="detail-route-${sourceIndex}">${item.route || '-'}</span></div>
                        <div class="info-row"><span class="info-label">产品</span><span class="info-value" id="detail-product-${sourceIndex}">${(item.detailMeta || {}).product_name || '-'}</span></div>
                        <div class="info-row"><span class="info-label">重量(kg)</span><span class="info-value" id="detail-weight-${sourceIndex}">${(item.detailMeta || {}).weight || '-'}</span></div>
                        <div class="info-row"><span class="info-label">承运商</span><span class="info-value" id="detail-carrier-${sourceIndex}">${(item.carrierInfo || {}).name || 'Unknown'}</span></div>
                        <div class="info-row"><span class="info-label">最新事件</span><span class="info-value" id="detail-last-event-${sourceIndex}">${item.lastOrderEvent || '-'}</span></div>
                        <div class="info-row"><span class="info-label">更新时间</span><span class="info-value">${item.shipment ? (item.shipment.modified || '-') : '-'}</span></div>
                    </div>
                </div>
            </td>
        `;
        tbody.appendChild(detailRow);
    });

    if (!data.length) {
        showError('暂无匹配的物流单');
    } else {
        showResults();
    }
}

function bindFilterTabs() {
    document.querySelectorAll('.filter-tab').forEach(tab => {
        tab.addEventListener('click', () => {
            const status = tab.dataset.status;
            setActiveFilter(status);
        });
    });
}

function setActiveFilter(status) {
    currentFilter = status;
    document.querySelectorAll('.filter-tab').forEach(tab =>
        tab.classList.toggle('active', tab.dataset.status === status)
    );
    renderTable();
}

function updateStatusCounts(data) {
    const filteredCounts = {
        all: data.length,
        processing: 0,
        transit: 0,
        delivered: 0,
        'not-found': 0,
        alert: 0,
        returned: 0
    };

    data.forEach(item => {
        const status = item.statusKey;
        if (filteredCounts.hasOwnProperty(status)) filteredCounts[status] += 1;
    });

    const totalCounts = {
        all: trackingData.length,
        processing: 0,
        transit: 0,
        delivered: 0,
        'not-found': 0,
        alert: 0,
        returned: 0
    };

    trackingData.forEach(item => {
        const status = item.statusKey;
        if (totalCounts.hasOwnProperty(status)) totalCounts[status] += 1;
    });

    const mapping = {
        processing: 'processingCount',
        transit: 'transitCount',
        delivered: 'deliveredCount',
        'not-found': 'notFoundCount',
        alert: 'alertCount',
        returned: 'returnedCount'
    };

    Object.entries(mapping).forEach(([status, elementId]) => {
        const el = document.getElementById(elementId);
        if (el) {
            const filteredValue = filteredCounts[status] || 0;
            const totalValue = totalCounts[status] || 0;
            el.textContent = filteredValue;
            el.setAttribute('title', `过滤结果: ${filteredValue} / 总计: ${totalValue}`);
        }
    });

    const allEl = document.getElementById('allCount');
    if (allEl) {
        allEl.textContent = filteredCounts.all;
        allEl.setAttribute('title', `过滤结果: ${filteredCounts.all} / 总计: ${totalCounts.all}`);
    }
}

function generateTimelineForItem(index, history) {
    const container = document.getElementById(`timeline-${index}`);
    if (!container) return;
    container.innerHTML = '';

    if (!history || !history.length) {
        container.innerHTML = '<p>暂无跟踪历史</p>';
        return;
    }

    const sortedHistory = history
        .slice()
        .sort((a, b) => new Date(b.timestamp || '') - new Date(a.timestamp || ''));

    sortedHistory.forEach(event => {
        const div = document.createElement('div');
        div.className = 'timeline-item';
        div.innerHTML = `
            <div class="timeline-content">
                <div class="timeline-time">${formatTimelineTime(event.timestamp)}</div>
                <div class="timeline-event">${event.description || event.event || '-'}</div>
                ${event.location ? `<div class="timeline-location">${event.location}</div>` : ''}
            </div>
        `;
        container.appendChild(div);
    });
}

async function loadShipmentDetail(index, options = {}) {
    const item = trackingData[index];
    if (!item) return null;

    if (item.detailLoaded && item.detailHistory) {
        if (!options.silent) {
            generateTimelineForItem(index, item.detailHistory);
        }
        return item.detailHistory;
    }

    if (item.detailLoading && item.detailPromise) {
        try {
            await item.detailPromise;
        } catch (err) {
            if (!options.silent) {
                const container = document.getElementById(`timeline-${index}`);
                if (container) container.innerHTML = `<p>加载失败: ${err.message || err}</p>`;
            }
        }
        if (!options.silent && item.detailHistory) {
            generateTimelineForItem(index, item.detailHistory);
        }
        return item.detailHistory;
    }

    const keys = [...new Set([
        item.deliveryOrderNo,
        item.logisticsOrderNo,
        item.trackingNumber,
        item.lastMileTracking
    ].map(key => (key || '').trim()).filter(Boolean))];

    const container = document.getElementById(`timeline-${index}`);
    if (!options.silent) {
        if (!keys.length) {
            if (container) container.innerHTML = '<p>缺少可查询的单号</p>';
            return null;
        }
        if (container) container.innerHTML = '<p>正在加载轨迹...</p>';
    } else if (!keys.length) {
        return null;
    }

    const promise = frappe.call({
        method: 'upsystem.upsystem.api.batch_tracking',
        args: { tracking_numbers: keys }
    }).then(resp => {
        const message = resp.message || {};
        const list = message.data || [];
        const successItem = list.find(entry => entry && entry.success);

        if (!successItem) {
            item.detailHistory = [];
            item.detailLoaded = true;
            if (!options.silent && container) container.innerHTML = '<p>未查询到轨迹</p>';
            return [];
        }

        const snapshot = extractTrackSnapshot(successItem);
        const history = snapshot.history
            ? snapshot.history.map(ev => ({
                  timestamp: ev.timestamp || ev.process_time || '',
                  description: ev.description || ev.event || '',
                  location: ev.location || '',
                  status: ev.status || '',
                  event: ev.event || '',
                  country: ev.country || '',
                  province: ev.province || '',
                  city: ev.city || ''
              }))
            : [];
        const data = successItem.data || {};

        item.detailHistory = history;
        item.detailLoaded = true;
        item.lastOrderEvent = snapshot.event || item.lastOrderEvent;
        if (snapshot.route) {
            item.route = snapshot.route;
        }
        const dataCarrierInfo = data.carrier_info || {};
        item.detailMeta = {
            product_name: data.product_name || '',
            weight: data.weight !== undefined && data.weight !== null
                ? Number(data.weight).toFixed(3)
                : '',
            last_event: snapshot.event || '',
            route: snapshot.route || item.route || '',
            carrier_site: dataCarrierInfo.website || dataCarrierInfo.last_mile_site || ''
        };
        const newStatusKey = normalizeStatus(snapshot.status || item.statusKey);
        item.statusKey = newStatusKey;
        item.deliveryStatus = getStatusInfo(newStatusKey);
        const lastMile = (data.last_mile_tracking || '').trim();
        if (lastMile) {
            item.lastMileTracking = lastMile;
        }
        const carrierInfo = snapshot.carrierInfo || dataCarrierInfo || {};
        if (Object.keys(carrierInfo).length) {
            item.carrierInfo = carrierInfo;
        }

        if (!options.silent) {
            updateShipmentRowUI(index, item);
            generateTimelineForItem(index, history);
        }

        return history;
    }).catch(err => {
        if (!options.silent && container) {
            container.innerHTML = `<p>加载失败: ${err.message || err}</p>`;
        }
        console.error(err);
        item.detailHistory = [];
        item.detailLoaded = true;
        return [];
    }).finally(() => {
        item.detailLoading = false;
        item.detailPromise = null;
    });

    item.detailLoading = true;
    item.detailPromise = promise;
    return promise;
}

function updateShipmentRowUI(index, item) {
    const row = document.querySelector(`tr.tracking-row[data-index="${index}"]`);
    if (row) {
        const badge = row.querySelector('.status-badge');
        if (badge) {
            badge.className = `status-badge ${item.deliveryStatus.class}`;
            badge.innerHTML = `<span>${item.deliveryStatus.icon}</span><span>${item.deliveryStatus.text}</span>`;
        }
        const lastEventEl = row.querySelector('.last-event');
        if (lastEventEl) {
            lastEventEl.textContent = item.lastOrderEvent || '-';
        }
        const cells = row.querySelectorAll('td');
        if (cells && cells.length >= 13) {
            // 更新时间列与承运商外链
            cells[5].textContent = item.creationTimestamp ? formatTimelineTime(item.creationTimestamp) : '-';
            cells[6].textContent = item.checkInTime ? formatTimelineTime(item.checkInTime) : '-';
            cells[7].textContent = item.checkOutTime ? formatTimelineTime(item.checkOutTime) : '-';
            cells[8].textContent = item.deliveredTime ? formatTimelineTime(item.deliveredTime) : '-';
            cells[9].textContent = item.latestTimestamp ? formatTimelineTime(item.latestTimestamp) : '-';
            cells[12].innerHTML = renderCarrierCell(item);
        }
    }

    const detailEventEl = document.getElementById(`detail-last-event-${index}`);
    if (detailEventEl) {
        detailEventEl.textContent = item.lastOrderEvent || '-';
    }
    const detailLastMileEl = document.getElementById(`detail-last-mile-${index}`);
    if (detailLastMileEl) {
        detailLastMileEl.textContent = item.lastMileTracking || '-';
    }
    const detailRouteEl = document.getElementById(`detail-route-${index}`);
    if (detailRouteEl) {
        detailRouteEl.textContent = (item.detailMeta && item.detailMeta.route) || item.route || '-';
    }
    const detailProductEl = document.getElementById(`detail-product-${index}`);
    if (detailProductEl) {
        detailProductEl.textContent = (item.detailMeta && item.detailMeta.product_name) || '-';
    }
    const detailWeightEl = document.getElementById(`detail-weight-${index}`);
    if (detailWeightEl) {
        detailWeightEl.textContent = (item.detailMeta && item.detailMeta.weight) || '-';
    }
    const detailCarrierEl = document.getElementById(`detail-carrier-${index}`);
    if (detailCarrierEl) {
        const carrierName = (item.carrierInfo || {}).name || 'Unknown';
        const carrierSite = (item.detailMeta && item.detailMeta.carrier_site) || (item.carrierInfo || {}).website || '';
        if (carrierSite) {
            detailCarrierEl.innerHTML = `<a href="${carrierSite}" target="_blank" rel="noopener noreferrer">${carrierName}</a>`;
        } else {
            detailCarrierEl.textContent = carrierName;
        }
    }
    const detailTrackingEl = document.getElementById(`detail-tracking-${index}`);
    if (detailTrackingEl) {
        detailTrackingEl.textContent = item.trackingNumber || '-';
    }

    updateStatusCounts(renderedData);
}

function toggleTrackingDetail(rowElement, detailElement) {
    if (!rowElement || !detailElement) return;

    const alreadyOpen = rowElement.classList.contains('selected');
    const index = Number(rowElement.dataset.index);

    document.querySelectorAll('.tracking-row').forEach(r => r.classList.remove('selected'));
    document.querySelectorAll('.tracking-detail').forEach(r => {
        r.classList.remove('expanded');
        r.style.display = 'none';
    });

    if (!alreadyOpen) {
        rowElement.classList.add('selected');
        detailElement.classList.add('expanded');
        detailElement.style.display = 'table-row';
        loadShipmentDetail(index);
    }
}

function getStatusInfo(status) {
    const normalized = normalizeStatus(status);
    const statusMap = {
        delivered: { text: 'Delivered', icon: '✓', class: 'delivered' },
        transit: { text: 'In Transit', icon: '✈', class: 'transit' },
        processing: { text: 'Processing', icon: '⚙', class: 'processing' },
        'not-found': { text: 'Not Found', icon: '✗', class: 'not-found' },
        alert: { text: 'Alert', icon: '⚠', class: 'alert' },
        returned: { text: 'Returned', icon: '↻', class: 'returned' }
    };
    return statusMap[normalized] || statusMap.processing;
}

function formatTimelineTime(ts) {
    if (!ts) return '-';
    const date = new Date(ts);
    if (Number.isNaN(date.getTime())) return ts;
    return date.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        timeZone: 'Asia/Shanghai'
    });
}

function renderCarrierCell(item) {
    const carrierName = (item.carrierInfo || {}).name || 'Unknown';
    const carrierSite = (item.detailMeta && item.detailMeta.carrier_site) || (item.carrierInfo || {}).website || '';
    if (carrierSite) {
        return `<a href="${carrierSite}" target="_blank" rel="noopener noreferrer">${carrierName}</a>`;
    }
    return carrierName;
}

async function copyTrackingHistory(index) {
    const item = trackingData[index];
    if (!item) return;
    if (!item.detailHistory || !item.detailHistory.length) {
        try {
            await loadShipmentDetail(index, { silent: true });
        } catch (err) {
            console.error(err);
        }
    }
    if (!item.detailHistory || !item.detailHistory.length) {
        frappe.msgprint(__('暂无轨迹可复制'));
        return;
    }
    const text = item.detailHistory.map(ev =>
        `${formatTimelineTime(ev.timestamp)}: ${ev.description || ev.event || '-'}`
    ).join('\n');
    navigator.clipboard.writeText(text).then(() => {
        frappe.msgprint(__('跟踪历史已复制到剪贴板'));
    }).catch(err => console.error(err));
}

function copyLink(index) {
    const item = trackingData[index];
    if (!item) return;
    const link = `${window.location.origin}${window.location.pathname}?tracking=${item.trackingNumber}`;
    navigator.clipboard.writeText(link).then(() => {
        frappe.msgprint(__('跟踪链接已复制到剪贴板'));
    }).catch(err => console.error(err));
}

function bindExport() {
    const exportBtn = document.getElementById('exportBtn');
    if (exportBtn) exportBtn.addEventListener('click', handleExport);
}

function handleExport() {
    const data = renderedData.length ? renderedData : trackingData;
    if (!data.length) {
        frappe.msgprint(__('没有数据可导出'));
        return;
    }
    const headers = ['运单号', '客户单号', '跟踪号', 'ERP订单', '运输方式', '收件人国家', '创建时间', '收货时间', '发货时间', '签收时间', '最新事件时间', '最新事件', '状态', '承运商'];
    const rows = data.map(item => [
        item.deliveryOrderNo || '',
        item.orderNumber || '',
        item.trackingNumber || '',
        `${item.orderName} / ${item.orderNumber}`,
        item.productName || '',
        item.destinationCode || '',
        item.creationTimestamp ? formatTimelineTime(item.creationTimestamp) : '',
        item.checkInTime ? formatTimelineTime(item.checkInTime) : '',
        item.checkOutTime ? formatTimelineTime(item.checkOutTime) : '',
        item.deliveredTime ? formatTimelineTime(item.deliveredTime) : '',
        item.latestTimestamp ? formatTimelineTime(item.latestTimestamp) : '',
        item.lastOrderEvent || '',
        item.deliveryStatus ? item.deliveryStatus.text : '',
        (item.carrierInfo && item.carrierInfo.name) ? item.carrierInfo.name : ''
    ]);
    const csv = [headers, ...rows]
        .map(row => row.map(field => `"${(field || '').replace(/"/g, '""')}"`).join(','))
        .join('\n');
    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `shop_shipments_${new Date().toISOString().slice(0, 10)}.csv`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
}

function showLoading() {
    document.getElementById('trackingResults').style.display = 'none';
    document.getElementById('errorState').style.display = 'none';
    document.getElementById('loadingState').style.display = 'block';
}

function showResults() {
    document.getElementById('loadingState').style.display = 'none';
    document.getElementById('errorState').style.display = 'none';
    document.getElementById('trackingResults').style.display = renderedData.length ? 'block' : 'none';
}

function showError(message) {
    document.getElementById('loadingState').style.display = 'none';
    document.getElementById('trackingResults').style.display = 'none';
    const errorDiv = document.getElementById('errorState');
    if (errorDiv) {
        document.getElementById('errorMessage').textContent = message;
        errorDiv.style.display = 'block';
    }
}
</script>
{% endblock %}

{% block footer %}{% endblock %}
